import os
import sys
import shutil
import subprocess  # 用于调用 cmd 命令
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, 
                            QLabel, QPushButton, QListWidget, QListWidgetItem, QTextEdit, 
                            QProgressBar, QFileDialog, QMessageBox, QDialog)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont


class FolderSelectionDialog(QDialog):
    """文件夹多选对话框（支持添加父文件夹及子文件夹）"""
    def __init__(self, parent=None, caption="选择文件夹", directory=""):
        super().__init__(parent)
        self.setWindowTitle(caption)
        self.resize(600, 400)
        
        self.selected_folders = []
        self.current_dir = directory
        
        # 创建布局
        layout = QVBoxLayout(self)
        
        # 列表显示已选文件夹
        self.list_view = QListWidget()
        layout.addWidget(self.list_view)
        
        # 按钮区
        btn_layout = QHBoxLayout()
        
        self.add_btn = QPushButton("添加单个文件夹")
        self.add_btn.clicked.connect(self.add_folder)
        btn_layout.addWidget(self.add_btn)
        
        self.add_parent_btn = QPushButton("添加父文件夹（包含子文件夹）")
        self.add_parent_btn.clicked.connect(self.add_parent_folder)
        btn_layout.addWidget(self.add_parent_btn)
        
        self.remove_btn = QPushButton("移除选中")
        self.remove_btn.clicked.connect(self.remove_folder)
        btn_layout.addWidget(self.remove_btn)
        
        self.ok_btn = QPushButton("确定")
        self.ok_btn.clicked.connect(self.accept)
        btn_layout.addWidget(self.ok_btn)
        
        self.cancel_btn = QPushButton("取消")
        self.cancel_btn.clicked.connect(self.reject)
        btn_layout.addWidget(self.cancel_btn)
        
        layout.addLayout(btn_layout)
    
    def add_folder(self):
        """添加单个文件夹"""
        folder = QFileDialog.getExistingDirectory(
            self, "选择单个文件夹", self.current_dir
        )
        if folder and folder not in self.selected_folders:
            self.selected_folders.append(folder)
            self.list_view.addItem(folder)
            self.current_dir = folder
    
    def add_parent_folder(self):
        """添加父文件夹，并自动导入其所有直接子文件夹"""
        parent_folder = QFileDialog.getExistingDirectory(
            self, "选择父文件夹", self.current_dir
        )
        if not parent_folder:
            return
        
        try:
            subfolders = []
            for entry in os.scandir(parent_folder):
                if entry.is_dir() and not entry.name.startswith('.'):
                    subfolders.append(entry.path)
            
            if not subfolders:
                QMessageBox.information(self, "提示", f"所选父文件夹下没有子文件夹")
                return
            
            added_count = 0
            for folder in subfolders:
                if folder not in self.selected_folders:
                    self.selected_folders.append(folder)
                    self.list_view.addItem(folder)
                    added_count += 1
            
            self.current_dir = parent_folder
            QMessageBox.information(self, "成功", f"已添加 {added_count} 个子文件夹（共 {len(subfolders)} 个）")
        
        except Exception as e:
            QMessageBox.critical(self, "错误", f"获取子文件夹失败：{str(e)}")
    
    def remove_folder(self):
        """移除选中的文件夹"""
        for item in self.list_view.selectedItems():
            row = self.list_view.row(item)
            del self.selected_folders[row]
            self.list_view.takeItem(row)
    
    def get_folders(self):
        """返回选中的文件夹列表"""
        return self.selected_folders


class CustomListWidget(QListWidget):
    """自定义列表控件，支持带删除按钮的列表项"""
    def __init__(self, parent=None):
        super().__init__(parent)
        self.item_list = []  # 存储实际路径（与列表项对应）

    def add_item_with_button(self, display_text, real_path, is_file):
        """添加带删除按钮的列表项"""
        # 创建自定义列表项
        item = QListWidgetItem()
        self.addItem(item)
        
        # 创建包含文本和按钮的widget
        widget = QWidget()
        layout = QHBoxLayout(widget)
        layout.setContentsMargins(5, 2, 5, 2)
        
        # 添加文本标签
        label = QLabel(display_text)
        label.setTextInteractionFlags(Qt.TextSelectableByMouse)  # 支持文本选中
        layout.addWidget(label, 1)  # 占大部分空间

        # 添加删除按钮（根据类型设置颜色及悬浮效果）
        delete_btn = QPushButton("×删除")
        delete_btn.setFixedSize(50, 50)

        # 基础样式 + 悬浮效果（包含缩放动画）
        if is_file:
            # 文件 - 黄色按钮（带悬浮效果）
            delete_btn.setStyleSheet("""
                QPushButton {
                    border-radius: 12px; 
                    font-weight: bold;
                    font-size: 16px;
                    background-color: #FFC107; 
                    color: black;
                    transition: transform 0.2s;  /* 平滑过渡动画 */
                }
                QPushButton:hover {
                    background-color: #FFA000;
                    color: white;
                    border: 2px solid #F57C00;
                    transform: scale(1.5);  /* 悬浮时放大1.5倍 */
                }
            """)
        else:
            # 文件夹 - 绿色按钮（带悬浮效果）
            delete_btn.setStyleSheet("""
                QPushButton {
                    border-radius: 12px; 
                    font-weight: bold;
                    font-size: 16px;
                    background-color: #4CAF50; 
                    color: white;
                    transition: transform 0.2s;  /* 平滑过渡动画 */
                }
                QPushButton:hover {
                    background-color: #388E3C;
                    color: white;
                    border: 2px solid #1B5E20;
                    transform: scale(1.5);  /* 悬浮时放大1.5倍 */
                }
            """)
        # 绑定删除事件（通过闭包传递当前索引）
        def create_delete_func(index):
            def delete_item():
                # 从列表中移除
                self.takeItem(index)
                # 从实际路径列表中移除
                del self.item_list[index]
                # 重新绑定后续按钮的索引
                self.rebind_buttons()
            return delete_item
        
        current_index = self.count() - 1
        delete_btn.clicked.connect(create_delete_func(current_index))
        layout.addWidget(delete_btn)
        
        # 设置widget为列表项的显示组件
        self.setItemWidget(item, widget)
        # 调整项高度
        item.setSizeHint(widget.sizeHint())
        # 保存实际路径
        self.item_list.append(real_path)

    def rebind_buttons(self):
        """重新绑定所有按钮的删除事件（解决索引偏移问题）"""
        for i in range(self.count()):
            item = self.item(i)
            widget = self.itemWidget(item)
            # 获取按钮（布局中的第二个元素）
            delete_btn = widget.findChild(QPushButton)
            # 移除旧连接
            try:
                delete_btn.disconnect()
            except:
                pass
            # 绑定新的删除事件
            def create_delete_func(index):
                def delete_item():
                    self.takeItem(index)
                    del self.item_list[index]
                    self.rebind_buttons()
                return delete_item
            delete_btn.clicked.connect(create_delete_func(i))

    def clear_all(self):
        """清空列表"""
        self.clear()
        self.item_list.clear()


class MultiFolderCopyGUI(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("多文件夹批量复制工具（集成Robocopy）")
        self.resize(900, 650)
        self.setMinimumSize(800, 600)
        
        # 初始化界面
        self.init_ui()
        
        # 当前路径
        self.current_path = os.path.dirname(os.path.abspath(__file__))

    def init_ui(self):
        # 主Widget和布局
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)
        main_layout.setContentsMargins(10, 10, 10, 10)
        main_layout.setSpacing(8)
        
        # -------------------------- 1. 待复制项选择区域 --------------------------
        source_label = QLabel("1. 选择需要复制的文件或文件夹:")
        source_label.setFont(QFont("微软雅黑", 10, QFont.Bold))
        main_layout.addWidget(source_label)
        
        # 选择按钮区
        source_btn_layout = QHBoxLayout()
        main_layout.addLayout(source_btn_layout)
        
        self.add_file_btn = QPushButton("添加文件...")
        self.add_file_btn.clicked.connect(self.add_files)
        source_btn_layout.addWidget(self.add_file_btn)
        
        self.add_folder_btn = QPushButton("添加文件夹...")
        self.add_folder_btn.clicked.connect(self.add_folders)
        source_btn_layout.addWidget(self.add_folder_btn)
        
        self.clear_source_btn = QPushButton("清除全部")
        self.clear_source_btn.clicked.connect(self.clear_all_items)
        source_btn_layout.addWidget(self.clear_source_btn)
        
        # 带删除按钮的待复制列表
        self.copy_list = CustomListWidget()
        self.copy_list.setAlternatingRowColors(True)
        main_layout.addWidget(self.copy_list)
        
        # 删除选中项按钮（保留批量删除功能）
        self.del_item_btn = QPushButton("删除选中项")
        self.del_item_btn.clicked.connect(self.remove_selected_items)
        main_layout.addWidget(self.del_item_btn)
        
        # -------------------------- 2. 目标文件夹选择区域 --------------------------
        target_label = QLabel("2. 选择目标文件夹 (可多选):")
        target_label.setFont(QFont("微软雅黑", 10, QFont.Bold))
        main_layout.addWidget(target_label)
        
        # 按钮区
        target_btn_layout = QHBoxLayout()
        main_layout.addLayout(target_btn_layout)
        
        self.add_target_btn = QPushButton("添加目标文件夹...")
        self.add_target_btn.clicked.connect(self.add_target_folders)
        target_btn_layout.addWidget(self.add_target_btn)
        
        self.clear_target_btn = QPushButton("清除全部")
        self.clear_target_btn.clicked.connect(self.clear_target_folders)
        target_btn_layout.addWidget(self.clear_target_btn)
        
        # 带删除按钮的目标文件夹列表
        self.target_list = CustomListWidget()
        self.target_list.setAlternatingRowColors(True)
        main_layout.addWidget(self.target_list)
        
        # 删除选中目标文件夹按钮（保留批量删除功能）
        self.del_target_btn = QPushButton("删除选中目标文件夹")
        self.del_target_btn.clicked.connect(self.remove_selected_targets)
        main_layout.addWidget(self.del_target_btn)
        
        # -------------------------- 操作按钮区 --------------------------
        op_btn_layout = QHBoxLayout()
        main_layout.addLayout(op_btn_layout)
        
        self.start_btn = QPushButton("开始复制")
        self.start_btn.setFont(QFont("微软雅黑", 9, QFont.Bold))
        self.start_btn.setStyleSheet("background-color: #4CAF50; color: white;")
        self.start_btn.clicked.connect(self.start_copy)
        op_btn_layout.addWidget(self.start_btn)
        
        self.clear_log_btn = QPushButton("清除日志")
        self.clear_log_btn.clicked.connect(self.clear_log)
        op_btn_layout.addWidget(self.clear_log_btn)
        
        # -------------------------- 进度条 --------------------------
        progress_label = QLabel("复制进度:")
        main_layout.addWidget(progress_label)
        
        self.progress_bar = QProgressBar()
        self.progress_bar.setRange(0, 100)
        self.progress_bar.setValue(0)
        main_layout.addWidget(self.progress_bar)
        
        # -------------------------- 日志区域 --------------------------
        log_label = QLabel("操作日志:")
        main_layout.addWidget(log_label)
        
        self.log_text = QTextEdit()
        self.log_text.setReadOnly(True)
        self.log_text.setMinimumHeight(100)
        main_layout.addWidget(self.log_text)

    # -------------------------- 待复制项操作 --------------------------
    def add_files(self):
        """添加文件到待复制列表"""
        files, _ = QFileDialog.getOpenFileNames(
            self, "选择要复制的文件", self.current_path, "所有文件 (*)"
        )
        if files:
            for file in files:
                # 避免重复添加
                if file not in self.copy_list.item_list:
                    # 显示文本：[文件] + 路径
                    display_text = f"[文件] {file}"
                    self.copy_list.add_item_with_button(display_text, file, is_file=True)
            self.current_path = os.path.dirname(files[0])

    def add_folders(self):
        """添加文件夹到待复制列表"""
        dialog = FolderSelectionDialog(
            self, "选择要复制的文件夹", self.current_path
        )
        if dialog.exec_():
            folders = dialog.get_folders()
            if folders:
                for folder in folders:
                    if folder not in self.copy_list.item_list:
                        # 显示文本：[文件夹] + 路径
                        display_text = f"[文件夹] {folder}"
                        self.copy_list.add_item_with_button(display_text, folder, is_file=False)
                self.current_path = os.path.dirname(folders[0])

    def clear_all_items(self):
        """清除所有待复制项"""
        self.copy_list.clear_all()

    def remove_selected_items(self):
        """删除选中的待复制项（批量删除）"""
        # 从后往前删，避免索引问题
        for item in reversed(self.copy_list.selectedItems()):
            row = self.copy_list.row(item)
            self.copy_list.takeItem(row)
            del self.copy_list.item_list[row]
        # 重新绑定按钮事件
        self.copy_list.rebind_buttons()

    # -------------------------- 目标文件夹操作 --------------------------
    def add_target_folders(self):
        """添加目标文件夹"""
        dialog = FolderSelectionDialog(
            self, "选择目标文件夹", self.current_path
        )
        if dialog.exec_():
            folders = dialog.get_folders()
            if folders:
                for folder in folders:
                    if folder not in self.target_list.item_list:
                        self.target_list.add_item_with_button(folder, folder, is_file=False)
                self.current_path = os.path.dirname(folders[0])

    def clear_target_folders(self):
        """清除所有目标文件夹"""
        self.target_list.clear_all()

    def remove_selected_targets(self):
        """删除选中的目标文件夹（批量删除）"""
        for item in reversed(self.target_list.selectedItems()):
            row = self.target_list.row(item)
            self.target_list.takeItem(row)
            del self.target_list.item_list[row]
        self.target_list.rebind_buttons()

    # -------------------------- 日志和进度条 --------------------------
    def log(self, message):
        self.log_text.append(message)
        self.log_text.moveCursor(self.log_text.textCursor().End)

    def clear_log(self):
        self.log_text.clear()

    # -------------------------- 核心复制功能（集成Robocopy命令） --------------------------
    # 只展示核心修改的start_copy函数，其他代码保持不变
    def start_copy(self):
        """混合方案：文件用shutil，文件夹用robocopy"""
        items_to_copy = self.copy_list.item_list
        target_folders = self.target_list.item_list
        
        # 验证输入
        if not items_to_copy:
            QMessageBox.critical(self, "错误", "请至少选择一个文件或文件夹进行复制！")
            return
        if not target_folders:
            QMessageBox.critical(self, "错误", "请至少选择一个目标文件夹！")
            return

        total_items = len(items_to_copy)
        total_targets = len(target_folders)
        total_operations = total_items * total_targets
        completed = 0

        self.log("===== 开始复制操作（混合模式） =====")
        self.log(f"待复制项总数: {total_items} 个")
        self.log(f"目标文件夹: {total_targets} 个")

        # 遍历所有目标文件夹
        for target_idx, target_folder in enumerate(target_folders, 1):
            self.log(f"\n处理目标文件夹 {target_idx}/{total_targets}: {target_folder}")
            
            # 遍历所有待复制项
            for item_idx, item in enumerate(items_to_copy, 1):
                item_name = os.path.basename(item)
                target_path = os.path.join(target_folder, item_name)
                item_is_file = os.path.isfile(item)

                try:
                    os.makedirs(target_folder, exist_ok=True)

                    if item_is_file:
                        # 文件复制：使用shutil.copy2
                        # 先检查目标文件是否存在，存在则删除（实现覆盖）
                        if os.path.exists(target_path):
                            os.remove(target_path)
                        shutil.copy2(item, target_path)
                        self.log(f"  文件 {item_idx}/{total_items}: {item_name} [复制成功（shutil）]")
                    else:
                        # 文件夹复制：使用robocopy
                        cmd = [
                            "robocopy", item, target_path,
                            "/E", "/MIR", "/R:3", "/W:2", "/NP"
                        ]

                        result = subprocess.run(
                            cmd,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE,
                            text=True,
                            shell=True
                        )

                        # 处理robocopy返回码（0-7为正常）
                        return_code = result.returncode
                        if return_code <= 7:
                            if return_code == 0:
                                status = "[无变化，源和目标一致]"
                            else:
                                status = "[复制成功（robocopy）]"
                            self.log(f"  文件夹 {item_idx}/{total_items}: {item_name} {status}")
                        else:
                            error_msg = result.stderr.strip() or f"错误（返回码{return_code}）"
                            self.log(f"  文件夹错误 {item_idx}/{total_items}: {item_name} → {error_msg}")

                except Exception as e:
                    if item_is_file:
                        self.log(f"  文件错误 {item_idx}/{total_items}: {item_name} → {str(e)}")
                    else:
                        self.log(f"  文件夹错误 {item_idx}/{total_items}: {item_name} → {str(e)}")

                # 更新进度
                completed += 1
                progress = int((completed / total_operations) * 100)
                self.progress_bar.setValue(progress)
                QApplication.processEvents()

        self.log("\n===== 操作完成 =====")
        QMessageBox.information(self, "完成", "所有复制操作已完成！")
        self.progress_bar.setValue(100)
    


if __name__ == "__main__":
    app = QApplication(sys.argv)
    font = QFont("SimHei")
    app.setFont(font)
    window = MultiFolderCopyGUI()
    window.show()
    sys.exit(app.exec_())